package com.jtpay.payresulthelper.service;

import android.accessibilityservice.AccessibilityService;
import android.content.*;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
import android.text.TextUtils;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.Toast;

import com.jtpay.payresulthelper.R;
import com.jtpay.payresulthelper.model.AliPayQueryModel;
import com.jtpay.payresulthelper.util.ActivityHelper;
import com.jtpay.payresulthelper.util.LogUtil;
import com.jtpay.payresulthelper.util.PayContext;

import java.util.ArrayList;
import java.util.List;

import static com.jtpay.payresulthelper.constant.HooKConstant.*;
import static com.jtpay.payresulthelper.provider.AliDbDataProvider.getAliAccount;
import static com.jtpay.payresulthelper.util.ActivityHelper.*;
import static com.jtpay.payresulthelper.util.PayContext.*;


public class AliAccessibilityService extends AccessibilityService {
    private boolean needHandleBack = false;//ali back to home ui
    private Handler mHandler = new Handler();
    private OrderReceiver mOrderReceiver = new OrderReceiver();
    private boolean isRegisterReceiver;
    private int billClickIndex = 0;
    private boolean scrollBreak;//list view  scroll up exit
    private boolean needBreakNow;//stop
    private boolean needRefresh;//scroll down refresh
    private boolean inClickListItemInOrder;//scroll down refresh
    private String returnProgramStatus = "0";//0 default 1 verify ali finish 2 product finish
    private ListItemInOrderCycleRunnable listItemInOrderCycleRunnable = new ListItemInOrderCycleRunnable();
    private AliPayQueryModel mQueryModel;

    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        // 获取当前事件的包名
        CharSequence charSequence = event.getPackageName();
        if (charSequence == null) {
            return;
        }
        String nowPackageName = charSequence.toString();
        // 判断是否为支付宝应用、并判断当前状态是否为运行状态
        if (nowPackageName.equals(ALI_PACKAGE_NAME)) {
            // 获取事件活动的窗口布局根节点
            AccessibilityNodeInfo rootNode = this.getRootInActiveWindow();
            String className = event.getClassName().toString();
//            LogUtil.log("className : " + className);
            switch (className) {
                case ALI_BILL_LIST_ACTIVITY_:
                    LogUtil.log("ALI_BILL_LIST_ACTIVITY_");
                    if (PayContext.isFirst) {
                        PayContext.isFirst = false;
                        performGlobalAction(GLOBAL_ACTION_BACK);
                        ActivityHelper.startBillList();
                        break;
                    }
                    if (BILL_STATUS == 1) {
                        resetStatus();
                        callBillCategoryGroupUI();
                    }
                    break;
                case "android.widget.ListView":
                    scrollBreak = checkScrollEnd(rootNode);
                    break;
                case ALI_LAUNCHER_ACTIVITY:
//                    handleHomeReturnProductProgram(rootNode);
                    break;
                default:
                    break;
            }
            // 判断是否为我们所需的窗口状态变化
            switch (event.getEventType()) {
                case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED:
                case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:
                    /*back to home page  when need*/
                    verifyAliAccount(rootNode);
                    handleBackButton(rootNode);
                    handleHomeReturnProductProgram(rootNode);
                    break;
            }
        }
    }

    private boolean checkScrollEnd(AccessibilityNodeInfo rootNode) {
        if (rootNode == null) {
            return true;
        }
        List<AccessibilityNodeInfo> list = rootNode.
                findAccessibilityNodeInfosByViewId("com.alipay.mobile.bill.list:id/list_more_text");
        return list != null && list.size() > 0;
        /*list = rootNode.
                findAccessibilityNodeInfosByViewId("com.alipay.mobile.bill.list:id/list_top_date_desc");
        return list != null && list.size() > 0 && !list.get(0).getText().toString().equals("当月");*/
    }

    private Runnable billCategoryGroupRunnable = new Runnable() {
        @Override
        public void run() {
            callBillCategoryGroupUI();
        }
    };
    private Runnable qrCodePayCategoryRunnable = new Runnable() {
        @Override
        public void run() {
            clickQrCodePayCategory();
        }
    };

    private class ListItemInOrderCycleRunnable implements Runnable {
        int index;

        void setIndex(int index) {
            this.index = index;
        }

        @Override
        public void run() {
            if (!inClickListItemInOrder && index > 0) {
                clickListItemInOrder();
                clickListItemInOrderCycle(index--);
            }
        }
    }

    private void callBillCategoryGroupUI() {
        if (BILL_STATUS != 1) {
            return;
        }
        BILL_STATUS = 2;
        boolean result = clickButton("com.alipay.mobile.bill.list:id/category_group_text");
        if (!result) {
            mHandler.postDelayed(billCategoryGroupRunnable, 500);
        } else {
            clickQrCodePayCategory();
        }
    }

    private void clickQrCodePayCategory() {
        boolean result = clickButton("com.alipay.mobile.bill.list:id/category_name", "小买卖");
        if (result) {
            BILL_STATUS = 3;
            switch (ORDER_TASK_STATUS) {
                case 2:
                    clickListItemFilterCycle();
                    break;
                default:
                    clickListItemInOrderCycle();
                    break;
            }
        } else {
            mHandler.postDelayed(qrCodePayCategoryRunnable, 500);
        }

    }


    private void clickListItemFilterCycle() {
        boolean result = clickButton("com.alipay.mobile.bill.list:id/top_calendar_icon");
        if (!result) {
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    clickListItemFilterCycle();
                }
            }, 500);
        } else {
            clickForDayCategory();
        }
    }

    private void clickForDayCategory() {
        String categoryText = getViewContent("com.alipay.mobile.bill.list:id/paramContent", 0);
        LogUtil.log("categoryText: " + categoryText);
        boolean result = true;
        if (categoryText != null && !categoryText.equals(getString(R.string.select_by_day))) {
            result = clickButton("com.alipay.mobile.bill.list:id/month_date_switch");
        }
        if (!result || categoryText == null) {
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    clickForDayCategory();
                }
            }, 500);
        } else {
            setDataAndRunNextDelay();
        }
    }

    private void setDataAndRunNextDelay() {
        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                setDataAndRunNext();
            }
        }, 500);
    }

    private void setDataAndRunNext() {
        List<AccessibilityNodeInfo> infoList = findViewListById("com.alipay.mobile.bill.list:id/calendar_text");
        List<AccessibilityNodeInfo> pickerInfoList = findViewListById("android:id/numberpicker_input");

        if (TextUtils.isEmpty(mQueryModel.getEndTimeFormat())
                || TextUtils.isEmpty(mQueryModel.getStartTimeFormat())) {
            LogUtil.log("setDataAndRunNext mQueryModel time error ");
            return;
        }

        if (infoList != null && infoList.size() >= 2
                && pickerInfoList != null && pickerInfoList.size() >= 3) {
            clickButtonWithRoot(pickerInfoList.get(0));
            inputText(mQueryModel.getStartTimeFormat().substring(0, 4));
            clickButtonWithRoot(pickerInfoList.get(1));
            inputText(mQueryModel.getStartTimeFormat().substring(4, 6));
            clickButtonWithRoot(pickerInfoList.get(2));
            inputText(mQueryModel.getStartTimeFormat().substring(6, 8));
            clickButtonWithRoot(pickerInfoList.get(0));
            clickButton(infoList.get(1));
            clickButtonWithRoot(pickerInfoList.get(2));
            inputText(mQueryModel.getEndTimeFormat().substring(6, 8));
            clickButtonWithRoot(pickerInfoList.get(1));
            inputText(mQueryModel.getEndTimeFormat().substring(4, 6));
            clickButtonWithRoot(pickerInfoList.get(0));
            inputKeyCode("67");
            inputText(mQueryModel.getEndTimeFormat().substring(0, 4));
            clickButtonWithRoot(pickerInfoList.get(2));
            clickButton("com.alipay.mobile.ui:id/title_bar_generic_button");
            clickListItemInOrderCycle();
        } else {
            setDataAndRunNextDelay();
        }
    }

    private void clickListItemInOrderCycle() {
        inClickListItemInOrder = false;
        clickListItemInOrderCycle(ACCESSIBILITY_SERVICE_ERROR_COUNT_DEF);
    }

    private void clickListItemInOrderCycle(int index) {
        listItemInOrderCycleRunnable.setIndex(index);
        mHandler.postDelayed(listItemInOrderCycleRunnable, 500);
    }

    private void clickListItemInOrder() {
        List<AccessibilityNodeInfo> list = getInfoList();
        if (needBreakNow) {
            needHandleBack = true;
            handleBackButton(getRootInActiveWindow());
            return;
        }
        /*List<String> dateList = getListContent("com.alipay.mobile.bill.list:id/timeInfo1");
        List<String> timeList = getListContent("com.alipay.mobile.bill.list:id/timeInfo2");
        if (desList.size() < 1) {

        }*/
        returnProgramStatus = "2";
        if (list == null || list.size() < 1) {
            LogUtil.log("list.size 0  wait for next");
        } else if (list.size() > billClickIndex) {
            LogUtil.log("list.size : " + list.size());
            inClickListItemInOrder = true;
            clickButton(list.get(billClickIndex));
        } else {
            billClickIndex = 0;
//            inputSwipe(100, 300, 100, 1800);
            if (scrollBreak && needRefresh) {
                BILL_STATUS = 0;
                inputSwipe(100, 300, 100, 1800);
                needRefresh = false;
                clickListItemInOrderCycle();
                return;
            } else if (scrollBreak) {
                BILL_STATUS = 0;
                return;
            }
            inputSwipe(100, 1800, 100, 300);
            clickListItemInOrderCycle();
        }
    }

    private List<AccessibilityNodeInfo> getInfoList() {
        AccessibilityNodeInfo rootInfo = getRootInActiveWindow();
        if (rootInfo == null) {
            return null;
        }
        return rootInfo.findAccessibilityNodeInfosByViewId(
                "com.alipay.mobile.bill.list:id/listItem");
    }

    /* verify ali account service*/
    private void verifyAliAccount(AccessibilityNodeInfo info) {
        if (info == null || PayContext.VerifyAccountStatus != 1) {
            return;
        }
        if (info.getChildCount() == 0) {
            returnProgramStatus = "1";
            BILL_STATUS = 0;
            if (info.getText() != null
                    && info.getText().toString().contains(getString(R.string.ali_personal_page))) {
                clickButton(info);
                return;
            }
            AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();
            List<AccessibilityNodeInfo> list;
            try {
                list = nodeInfo.findAccessibilityNodeInfosByViewId
                        ("com.alipay.android.phone.wallet.profileapp:id/tv_right");
            } catch (Exception e) {
                e.printStackTrace();
                LogUtil.log("findAccessibility NodeInfo ByViewId error : " + e.getMessage());
                return;
            }
            if (list != null && list.size() > 0) {
//                LogUtil.log(list.toString());
                String aliAccount = getAliAccount(this);
                if (aliAccount.length() < 1) {
                    aliAccount = ALI_ACCOUNT_DEF;
                }
                try {
                    VerifyAccountResult = list.get(0).getText().toString().equals(aliAccount);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                if (VerifyAccountResult) {
                    Intent intent = new Intent(ACTION_SET_ALI_ACCOUNT);
                    intent.putExtra(EXTRA_KEY_ALI_ACCOUNT, aliAccount);
                    sendBroadcast(intent);
                }
                needHandleBack = true;
                sendBroadcast(new Intent(ACTION_VERIFY_RESULT));
                PayContext.VerifyAccountStatus = 2;
            }

        } else {
            // 当前节点 有子控件时，解析它的孩子，以此递归
            for (int i = 0; i < info.getChildCount(); i++) {
                if (info.getChild(i) != null) {
                    verifyAliAccount(info.getChild(i));
                }
            }
        }
    }

    /**
     * @param info AccessibilityNodeInfo
     */
    private void handleBackButton(AccessibilityNodeInfo info) {
        if (info == null || !needHandleBack) {
            return;
        }
        if (info.getChildCount() == 0) {
            // 返回按钮
            AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();
            if (nodeInfo != null) {
                // 根据id查找需要点击的节点，返回的是一个List
                clickButton("com.alipay.mobile.antui:id/back_button");
                clickButton("com.alipay.mobile.ui:id/title_bar_back_button");
                clickButton("com.alipay.mobile.nebula:id/h5_tv_nav_back");
            }
        } else {
            // 当前节点 有子控件时，解析它的孩子，以此递归
            for (int i = 0; i < info.getChildCount(); i++) {
                if (info.getChild(i) != null) {
                    handleBackButton(info.getChild(i));
                }
            }
        }
    }

    /**
     * handleHomeReturnProductProgram
     *
     * @param info AccessibilityNodeInfo
     */
    private void handleHomeReturnProductProgram(AccessibilityNodeInfo info) {
        if (info == null || returnProgramStatus.equals("0")) {
            return;
        }
        if (info.getChildCount() == 0) {
            if (info.getText() != null && info.getText().toString().contains(getString(R.string.home_page))) {
                needHandleBack = false;
                switch (returnProgramStatus) {
                    case "1":
                        returnProgramStatus = "0";
                        PayContext.VerifyAccountStatus = 0;
                        ActivityHelper.startProgramActivity();
                        break;
                    case "2":
                        returnProgramStatus = "0";
                        ActivityHelper.startProgramActivity();
//                        MainActivity.instance.UIResumeAndUpload();
                        break;
                    default:
                        break;
                }
            }
        } else {
            // 当前节点 有子控件时，解析它的孩子，以此递归
            for (int i = 0; i < info.getChildCount(); i++) {
                if (info.getChild(i) != null) {
                    handleHomeReturnProductProgram(info.getChild(i));
                }
            }
        }
    }

    @Override
    public void onInterrupt() {
        Toast.makeText(this, "onInterrupt", Toast.LENGTH_SHORT).show();
    }

    @Override
    protected void onServiceConnected() {
        super.onServiceConnected();
        LogUtil.log("AccessibilityService onServiceConnected");
        registerReceiver();
    }

    @Override
    public boolean onUnbind(Intent intent) {
        LogUtil.log("AccessibilityService onUnbind");
        unRegisterReceiver();
        return super.onUnbind(intent);
    }

    private void clickButton(AccessibilityNodeInfo info) {
        AccessibilityNodeInfo parent = info;
        while (parent != null) {
            if (parent.isClickable()) {
                // 模拟点击，跳出循环
                parent.performAction(AccessibilityNodeInfo.ACTION_CLICK);
                break;
            }
            parent = parent.getParent();
        }
    }

    /**
     * @param viewId String resource-id
     * @param index  int index
     */
    private boolean clickButton(String viewId, int index) {
        List<AccessibilityNodeInfo> list = null;
        try {
            list = this.getRootInActiveWindow().findAccessibilityNodeInfosByViewId(viewId);
        } catch (Exception e) {
            e.printStackTrace();
//            log("findAccessibility NodeInfo ByViewId " + viewId + " error : " + e.getMessage());
        }
        // click
        if (list != null && list.size() >= index + 1) {
            clickButton(list.get(index));
            return true;
        }
        return false;
    }

    /**
     * @param viewId  String resource-id
     * @param content string
     * @return result
     */
    private boolean clickButton(String viewId, String content) {
        List<AccessibilityNodeInfo> list = null;
        try {
            list = this.getRootInActiveWindow().findAccessibilityNodeInfosByViewId(viewId);
        } catch (Exception e) {
            e.printStackTrace();
//            log("findAccessibility NodeInfo ByViewId " + viewId + " error : " + e.getMessage());
        }
        // click
        if (list != null && list.size() > 0) {
            for (AccessibilityNodeInfo info : list) {
                if (content.equals(info.getText().toString())) {
                    clickButton(info);
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * @param viewId String resource-id
     */
    private boolean clickButton(String viewId) {
        List<AccessibilityNodeInfo> list = null;
        try {
            list = getRootInActiveWindow().findAccessibilityNodeInfosByViewId(viewId);
        } catch (Exception e) {
            e.printStackTrace();
//            log("findAccessibility NodeInfo ByViewId " + viewId + " error : " + e.getMessage());
        }
        // click
        if (list != null && list.size() >= 1) {
            clickButton(list.get(0));
            return true;
        }
        return false;
    }

    /**
     * @param viewId String resource-id
     */
    private AccessibilityNodeInfo findViewById(String viewId, int index) {
        List<AccessibilityNodeInfo> list = null;
        try {
            list = getRootInActiveWindow().findAccessibilityNodeInfosByViewId(viewId);
        } catch (Exception e) {
            e.printStackTrace();
//            log("findAccessibility NodeInfo ByViewId " + viewId + " error : " + e.getMessage());
        }
        if (list != null && list.size() > index) {
            return list.get(index);
        }
        return null;
    }

    /**
     * @param viewId String resource-id
     */
    private List<AccessibilityNodeInfo> findViewListById(String viewId) {
        List<AccessibilityNodeInfo> list = null;
        try {
            list = getRootInActiveWindow().findAccessibilityNodeInfosByViewId(viewId);
        } catch (Exception e) {
            e.printStackTrace();
//            log("findAccessibility NodeInfo ByViewId " + viewId + " error : " + e.getMessage());
        }
        return list;
    }

    /**
     * @param viewId String resource-id
     */
    private List<String> getListContent(String viewId) {
        List<String> list = new ArrayList<>();
        List<AccessibilityNodeInfo> listNodeInfo = null;
        try {
            listNodeInfo = getRootInActiveWindow().findAccessibilityNodeInfosByViewId(viewId);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (listNodeInfo == null || listNodeInfo.size() < 1) {
            return null;
        }
        for (AccessibilityNodeInfo nodeInfo : listNodeInfo) {
            list.add(nodeInfo.getText().toString());
        }
        return list;
    }

    /**
     * @param viewId String resource-id
     */
    private String getViewContent(String viewId, int index) {
        List<AccessibilityNodeInfo> listNodeInfo = null;
        try {
            listNodeInfo = getRootInActiveWindow().findAccessibilityNodeInfosByViewId(viewId);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (listNodeInfo == null || listNodeInfo.size() <= index) {
            return null;
        }
        return listNodeInfo.get(index).getText().toString();
    }

    /**
     * @param viewId String resource-id
     */
    private boolean setViewContent(String viewId, int index, String content) {
        List<AccessibilityNodeInfo> listNodeInfo = null;
        try {
            listNodeInfo = getRootInActiveWindow().findAccessibilityNodeInfosByViewId(viewId);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (listNodeInfo == null || listNodeInfo.size() <= index) {
            return false;
        }
        listNodeInfo.get(index).setText(content);
        return true;
    }

    private void clipboardPaste(AccessibilityNodeInfo info, String text) {
        if (info == null) {
            return;
        }
        ClipboardManager clipboardManager = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
        ClipData clipData = ClipData.newPlainText(null, text);
        if (clipboardManager == null) {
            return;
        }
        clipboardManager.setPrimaryClip(clipData);
        // 模拟粘贴
        info.performAction(AccessibilityNodeInfo.ACTION_FOCUS);
        info.performAction(AccessibilityNodeInfo.ACTION_PASTE);
    }

    private void setContent(AccessibilityNodeInfo info, String content) {
        if (info == null) {
            return;
        }
        Bundle arguments = new Bundle();
        arguments.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, content);
        info.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arguments);
    }

    /**
     * @param nodeInfo use root command click
     */
    private void clickButtonWithRoot(final AccessibilityNodeInfo nodeInfo) {
//        log("clickButtonWithRoot");
        Rect outBounds = new Rect();
        nodeInfo.getBoundsInScreen(outBounds);
        inputClick((outBounds.left + outBounds.right) / 2,
                (outBounds.top + outBounds.bottom) / 2);
    }

    private void registerReceiver() {
        if (isRegisterReceiver) {
            return;
        }
        isRegisterReceiver = true;
        IntentFilter intentFilter = new IntentFilter(ACTION_SIMULATE_CLICK_START);
        intentFilter.addAction(ACTION_SIMULATE_CLICK_CONTINUE);
        intentFilter.addAction(ACTION_DETAIL_FAIL_INFO);
        intentFilter.addAction(ACTION_SIMULATE_CLICK_STOP);
        registerReceiver(mOrderReceiver, intentFilter);
    }

    private void unRegisterReceiver() {
        isRegisterReceiver = false;
        unregisterReceiver(mOrderReceiver);
    }

    class OrderReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (action == null) {
                return;
            }
            LogUtil.log("OrderReceiver onReceive  " + action);
            switch (action) {
                case ACTION_SIMULATE_CLICK_START:
                    LogUtil.log("OrderReceiver BILL_STATUS  " + BILL_STATUS);
                    if (BILL_STATUS != 0) {
                        needRefresh = true;
                        break;
                    }
                    mQueryModel = intent.getParcelableExtra(EXTRA_KEY_PAY_MODEL);
                    if (mQueryModel != null) {
                        ORDER_TASK_STATUS = 2;
                    } else {
                        ORDER_TASK_STATUS = 1;
                    }
                    PayContext.BILL_STATUS = 1;
                    returnProgramStatus = "0";
                    needBreakNow = false;
                    ActivityHelper.startBillList();
                    break;
                case ACTION_SIMULATE_CLICK_CONTINUE:
                    sendBroadcast(new Intent(ACTION_UPLOAD_PAY_RESULT));
                    billClickIndex++;
                case ACTION_DETAIL_FAIL_INFO:
                    performGlobalAction(GLOBAL_ACTION_BACK);
                    mHandler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            clickListItemInOrder();
                        }
                    }, 500);
                    break;
                case ACTION_SIMULATE_CLICK_STOP:
                    needBreakNow = true;
                    needHandleBack = true;
                    BILL_STATUS = 0;
                    ORDER_TASK_STATUS = 0;
                    sendBroadcast(new Intent(ACTION_UPLOAD_PAY_RESULT));
                    handleBackButton(getRootInActiveWindow());
                    break;
                default:
                    break;
            }
        }
    }

    private void resetStatus() {
        scrollBreak = true;
        needBreakNow = false;
        needHandleBack = false;
        needRefresh = false;
        billClickIndex = 0;
    }

}